/**
 * \file intersection.hpp
 * 
 * \section COPYRIGHT
 *
 * Basis: A 3D Mathematics Library
 *
 * ---------------------------------------------------------------------
 *
 * Copyright (c) 2010, Don Olmstead
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *
 *  3. Neither the name of organization nor the names of its contributors may be
 *     used to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BASIS_INTERSECTION_HPP_INCLUDED
#define BASIS_INTERSECTION_HPP_INCLUDED

#include <basis/plane.hpp>
#include <basis/sphere.hpp>

namespace basis
{

	//------------------------------------------------------------
	// Plane intersection
	//------------------------------------------------------------

	/**
	 * Describes the intersection between a plane and a bounding volume.
	 */
	namespace plane_intersection
	{
		/// An enumerated type
		enum type
		{
			/// There is no intersection, and the volume is in the negative half-space of the plane.
			back,
			/// There is no intersection, and the volume is in the positive half-space of the plane.
			front,
			/// The plane is intersected.
			intersecting
		} ;

	} // end namespace plane_intersection

	/**
	 * Determines whether a point intersects with a plane.
	 *
	 * \relates plane
	 *
	 * \tparam Real A real number type.
	 * \tparam InstructionSet The SIMD instruction set to use.
	 *
	 * \param plane_value The plane to check intersection with.
	 * \param point The point to check intersection with.
	 * \returns An enumeration whether an intersection occurred.
	 */
	template <typename Real, typename InstructionSet>
	inline plane_intersection::type intersects(const plane<Real, InstructionSet>& plane_value, const vector3<Real, InstructionSet>& point)
	{
		Real distance_to = distance(plane_value, point);

		if (distance_to < (Real)0)
			return plane_intersection::back;
		else if (distance_to > (Real)0)
			return plane_intersection::front;
		else
			return plane_intersection::intersecting;
	}

	/**
	 * Determines whether a point intersects with a sphere.
	 *
	 * \relates plane
	 *
	 * \tparam Real A real number type.
	 * \tparam InstructionSet The SIMD instruction set to use.
	 *
	 * \param plane_value The plane to check intersection with.
	 * \param sphere_value The sphere to check intersection with.
	 * \returns An enumeration whether an intersection occurred.
	 */
	template <typename Real, typename InstructionSet>
	inline plane_intersection::type intersects(const plane<Real, InstructionSet>& plane_value, const sphere<Real, InstructionSet>& sphere_value)
	{
		Real distance_to = distance(plane_value, sphere_value.center());
		Real radius = sphere_value.radius();

		if (distance_to <= -radius)
			return plane_intersection::back;
		else if (distance_to >= radius)
			return plane_intersection::front;
		else
			return plane_intersection::intersecting;
	}

	//------------------------------------------------------------
	// Ray intersection
	//------------------------------------------------------------

	/**
	 * Determines whether a ray intersects with a sphere.
	 *
	 * \relates sphere
	 *
	 * \tparam Real A real number type.
	 * \tparam InstructionSet The SIMD instruction set to use.
	 *
	 * \pre Assumes the ray's direction is normalized.
	 * \param ray_value The ray to check intersection with.
	 * \param sphere_value The sphere to check intersection with.
	 * \returns \b true if an intersection occurred; \b false otherwise.
	 */
	template <typename Real, typename InstructionSet>
	bool intersects(const ray<Real, InstructionSet>& ray_value, const sphere<Real, InstructionSet>& sphere_value)
	{
		vector3<Real, InstructionSet> dif = ray_value.origin() - sphere_value.center();

	}

	//------------------------------------------------------------
	// Bounding volume intersection
	//------------------------------------------------------------

	/**
	 * Determines whether two spheres intersect.
	 *
	 * \relates sphere.
	 *
	 * \tparam Real A real number type.
	 * \tparam InstructionSet The SIMD instruction set to use.
	 *
	 * \param sphere1 The sphere to check intersection with.
	 * \param sphere2 The sphere to check intersection with.
	 * \returns \b true if an intersection occurred; \b false otherwise.
	 */
	template <typename Real, typename InstructionSet>
	bool intersects(const sphere<Real, InstructionSet>& sphere1, const sphere<Real, InstructionSet>& sphere2)
	{
		vector3<Real, InstructionSet> diff = sphere2.center() - sphere1.center();
		Real radiusSum = sphere2.radius() + sphere1.radius();

		return diff.length_squared() <= radiusSum * radiusSum;
	}

} // end namespace basis

#endif // end BASIS_INTERSECTION_HPP_INCLUDED
